package dict

type SampleDict struct {
	m map[string]interface{}
}

// NewSample returns a sample dict.
func NewSample() Dict {
	return makeSampleDict()
}

func makeSampleDict() *SampleDict {
	return &SampleDict{m: make(map[string]interface{})}
}

// Len returns number of KVs.
func (dict *SampleDict) Len() int {
	return len(dict.m)
}

// Get returns value corresponding to `key` and whether `key` exists.
func (dict *SampleDict) Get(key string) (val interface{}, exists bool) {
	val, exists = dict.m[key]
	return
}

// PutOrSet put a KV and returns 1 if `key` not exists, otherwise, set `val` for the `key` and returns 0.
func (dict *SampleDict) PutOrSet(key string, val interface{}) (result int) {
	_, exists := dict.m[key]
	dict.m[key] = val
	if exists {
		return 0
	}
	return 1
}

// PutIfNotExists put a KV if `key` not exists.
func (dict *SampleDict) PutIfNotExists(key string, val interface{}) (result int) {
	if _, exists := dict.m[key]; exists {
		return 0
	}
	dict.m[key] = val
	return 1
}

// SetIfExists set `val` for the `key` if `key` exists.
func (dict *SampleDict) SetIfExists(key string, val interface{}) (result int) {
	if _, exists := dict.m[key]; !exists {
		return 0
	}
	dict.m[key] = val
	return 1
}

// Remove removes element with `key` and returns 1 if `key` exists, otherwise, returns 0.
func (dict *SampleDict) Remove(keys ...string) (result int) {
	for _, key := range keys {
		_, exists := dict.m[key]
		if !exists {
			return 0
		}
		delete(dict.m, key)
		result++
	}
	return
}

// ForEach consumes element one by one with `consumer` until all elements run out or any consumer returns false;
//         returns whether all consumers return true.
func (dict *SampleDict) ForEach(consumer Consumer) bool {
	for k, v := range dict.m {
		if !consumer(k, v) {
			return false
		}
	}
	return true
}

// Keys returns slice of all keys.
func (dict *SampleDict) Keys() []string {
	keys := make([]string, 0, dict.Len())
	for k := range dict.m {
		keys = append(keys, k)
	}
	return keys
}

// RandomKeys returns `limit` keys, which may be duplicated.
func (dict *SampleDict) RandomKeys(limit int) []string {
	keys := make([]string, 0, dict.Len())
	for i := 0; i < limit; i++ {
		for k := range dict.m {
			keys = append(keys, k)
			break
		}
	}
	return keys
}

// RandomDistinctKeys returns at most `limit` keys, which are distinct.
func (dict *SampleDict) RandomDistinctKeys(limit int) []string {
	if limit > dict.Len() {
		return dict.Keys()
	}
	keys := make([]string, 0, limit)
	count := 0
	for k := range dict.m {
		count++
		if count > limit {
			break
		}
		keys = append(keys, k)
	}
	return keys
}

// Clear remove all KVs.
func (dict *SampleDict) Clear() {
	*dict = *makeSampleDict()
}
